State Tool: forward platform JWT + version User-Agent on the build-log-streamer WebSocket#3809
State Tool: forward platform JWT + version User-Agent on the build-log-streamer WebSocket#3809antoine-activestate wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the State Tool’s build-log-streamer WebSocket connection to forward identifying/auth data during the HTTP Upgrade so the server can authorize streams and monitor client versions.
Changes:
- Thread a platform JWT through runtime setup into build-log streaming, and offer it via
Sec-WebSocket-Protocolasbearer.<jwt>alongside the real subprotocol. - Send the standard, versioned
User-Agenton the WebSocket Upgrade request. - Add a new handshake-focused test that validates the server receives the expected
Sec-WebSocket-ProtocolandUser-Agentheaders.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/runtime/setup.go | Adds Opts.AuthToken and passes it into build-log streaming initialization. |
| pkg/runtime/options.go | Introduces WithAuthToken runtime option for forwarding the platform JWT. |
| pkg/runtime/internal/buildlog/buildlog.go | Stores the auth token on BuildLog and forwards it into the WS connect call. |
| pkg/platform/api/buildlogstream/streamer.go | Updates Connect to set subprotocols (including optional bearer.<jwt>) and send the versioned User-Agent. |
| pkg/platform/api/buildlogstream/streamer_test.go | Adds tests performing a real WS handshake and asserting request headers received by the server. |
| pkg/platform/api/api.go | Extracts package-level UserAgent() for reuse by the WS dialer. |
| internal/runbits/runtime/runtime.go | Wires prime.Auth().BearerToken() into runtime options via WithAuthToken. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
00ae6aa to
0fb5c95
Compare
… WebSocket The build-log-streamer WebSocket previously opened with only an Origin header, so the server had no way to authorize the stream. When the caller is authenticated, offer the platform JWT via Sec-WebSocket-Protocol as 'bearer.<jwt>' alongside the real 'build-log-streamer.activestate.com.v1' subprotocol the server echoes back (its allow-list contains only the real subprotocol, so the token never appears in the upgrade response). The browser WebSocket API can't set custom request headers, so the dashboard carries the JWT the same way -- both clients stay symmetric. Also send the versioned State Tool User-Agent on the Upgrade so the server can see which client versions are connecting. The token is threaded as a plain string from the runtime options into Connect, so pkg/runtime gains no authentication dependency; an empty token means anonymous (unchanged behavior). Includes a real-handshake test that asserts the offered subprotocols, the negotiated subprotocol, and the User-Agent the server receives.
0fb5c95 to
76781ec
Compare
|
I enabled the "critical" integration tests. We don't care so much about the ARM tests because those are expected to fail (we don't have any ARM Platform projects). However, I am seeing some concerning failures:
State Tool for the most part runs unauthenticated. This is by design. |
|
Dug into the three critical-suite failures — they're pre-existing, not introduced by this PR. The scheduled (nightly) integration suite on master has been red for ≥16 consecutive nights (back through at least 2026-05-17). The most recent nightly — Jun 1 01:04 UTC, on unchanged master, before this PR's latest push — fails on the identical That's a buildplanner dependency-resolution failure ( I'm raising the busted nightly as its own issue so it gets a dedicated fix (it looks platform-side — build-expr retrieval for the |
Summary
Makes the State Tool identify itself on the build-log-streamer WebSocket Upgrade so the server can authorize the stream and monitor connecting client versions.
Sec-WebSocket-Protocol. When authenticated, the client offersbearer.<jwt>alongside the real subprotocolbuild-log-streamer.activestate.com.v1(which the server echoes back; its allow-list contains only the real one, so the token never appears in the upgrade response). The browser WebSocket API can't set custom request headers, so the dashboard carries the JWT the same way — both clients stay symmetric.User-Agenton the Upgrade (constants.UserAgent) so the server can see which State Tool versions are connecting.Design note
The token is threaded as a plain string (
prime.Auth().BearerToken()→ runtime option →Connect), sopkg/runtimegains no dependency on the authentication package. Empty token = anonymous (unchanged behavior).Test plan
go build+ gofmt clean across touched packages.httptestWebSocket server asserting the offered subprotocols, the negotiated subprotocol (token never echoed back), and the User-Agent the server receives.go test -raceclean.Note
Full server-side JWT validation ships separately (infra repo); this client change degrades gracefully against the current server — an unknown subprotocol is ignored and anonymous still works.
Supersedes #3808 (closed when its branch was shortened to fix a macOS/Windows integration-test socket-path overflow).